/*
 * @(#)HtmlTextExtractor.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.dms.extractor;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FilterReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.rtf.RTFEditorKit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
  RtfTextExtractor.java

  This class is the text extractor for RTF files.

    @author          Rollo Chan
    @company         DCIVision Limited
    @creation date   26/08/2003
    @version         $Revision: 1.8.32.1 $
*/

public class RtfTextExtractor extends AbstractTextExtractor {

  public static final String REVISION = "$Revision: 1.8.32.1 $";

  private static final Log log = LogFactory.getLog(RtfTextExtractor.class);
   
  public RtfTextExtractor(InputStream fis, String encoding) {
    super(fis, encoding);
    if (fis==null) {
      return;
    }
    Reader reader = null;
    try {
      reader = new BufferedReader(new InputStreamReader(fis, encoding));
      WrappedRtfInputStream inDocument = new WrappedRtfInputStream(reader);
      DefaultStyledDocument dsd = new DefaultStyledDocument();
      RTFEditorKit rtfEditorKit = new RTFEditorKit();
      rtfEditorKit.read(inDocument, dsd, 0);
      text = dsd.getText(0, dsd.getLength());
    } catch (Exception e) {
      log.error(e, e);
    } finally {
      try { reader.close(); } catch (Exception ignore) {} finally { reader = null; }
    }
  }

}

class WrappedRtfInputStream extends FilterReader {

  /** Search string for start of the section. */
  private static final String SEC_START = "{\\stylesheet";

  /** Search string for end of the section. */
  private static final String SEC_END = "}}";

  /** Locale store for the document data. */
  private final StringBuffer strBuf = new StringBuffer();

  /**
   * Wrapper for the input stream used by the RTF parser.<br>
   * Here the complete document will be loaded into a string buffer
   * and the section causes the problems will be deleted.<br>
   * <br>
   *
   * @param in Stream reader for the document (e.g. {@link FileReader}).
   *
   * @throws IOException in case of I/O errors during document loading.
   */
  public WrappedRtfInputStream(final Reader in) throws IOException {
    super(in);

    int numchars;
    final char[] tmpbuf = new char[2048];

    // read the whole document into StringBuffer
    do {
      numchars = in.read(tmpbuf, 0, tmpbuf.length);

      if (numchars != -1) {
        strBuf.append(tmpbuf, 0, numchars);
      }
    } while (numchars != -1);

    // finally delete the problem making section
    deleteStylesheet();
  }

  /**
   * Deletion of the prblematic section.
   *
   */
  private void deleteStylesheet() {
    // find start of the section
    final int start = strBuf.indexOf(SEC_START);

    if (start == -1) {
      // section not contained, so just return ...
      return;
    }

    // find end of section
    final int end = strBuf.indexOf(SEC_END, start);

    // delete section
    strBuf.delete(start, end + 2);
  }


  /**
   * Read characters into a portion of an array.<br>
   * The data given back will be provided from local StringBuffer
   * which contains the whole document.
   *
   * @param buf Destination buffer.
   * @param off Offset at which to start storing characters -
   * <srong>NOT RECOGNIZED HERE.</strong>.
   * @param len Maximum number of characters to read.
   *
   * @return The number of characters read, or -1 if the end of the
   * stream has been reached
   *
   * @exception IOException If an I/O error occurs
   */
  public int read(final char[] buf, final int off, final int len) throws IOException {

    if (strBuf.length() == 0) {
      // if buffer is empty end of document is reached
      return -1;
    }

    // fill destination array
    int byteCount = 0;
    for (; byteCount < len; byteCount++) {

      if (byteCount == strBuf.length()) {
        // end reached, stop filling
        break;
      }

      // copy data to destination array
      buf[byteCount] = strBuf.charAt(byteCount);
    }

    // delete to copied data from local store
    strBuf.delete(0, byteCount);

    return byteCount;
  }
}
